package com.smedi.ismedi.constructionproject.core.application.query.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.smedi.ismedi.authority.starter.util.AuthorityUtil;
import com.smedi.ismedi.constructionproject.core.application.command.ProjectCountQueryCommand;
import com.smedi.ismedi.constructionproject.core.application.command.ProjectListQueryCommand;
import com.smedi.ismedi.constructionproject.core.application.command.ProjectOneQueryCommand;
import com.smedi.ismedi.constructionproject.core.application.command.ProjectPageQueryCommand;
import com.smedi.ismedi.constructionproject.core.application.query.ProjectBasicQueryService;
import com.smedi.ismedi.constructionproject.core.application.query.vo.ProjectBasicVo;
import com.smedi.ismedi.constructionproject.core.application.query.vo.ProjectDetailVo;
import com.smedi.ismedi.constructionproject.core.application.query.vo.ProjectWithDingVo;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.Project;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.ProjectBasic;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.ProjectWithDing;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.dto.ProjectCountQuery;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.dto.ProjectQuery;
import com.smedi.ismedi.constructionproject.core.domain.repository.ProjectBasicRepository;
import com.smedi.ismedi.constructionproject.core.domain.service.ProjectBasicDomainService;
import com.smedi.ismedi.constructionproject.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.constructionproject.core.infrastructure.enumerate.EpcTypeEnum;
import com.smedi.ismedi.constructionproject.core.infrastructure.enumerate.ProjectCategoryEnum;
import com.smedi.ismedi.constructionproject.core.infrastructure.enumerate.ProjectStatusEnum;
import com.smedi.ismedi.constructionproject.core.port.adapter.persistence.mybatis.mapper.ProjectBasicMapper;
import com.smedi.ismedi.constructionproject.core.port.adapter.service.OrganizationRemoteApiService;
import com.smedi.ismedi.organization.api.dto.response.HrOrganizationResponse;
import com.smedi.ismedi.organization.api.feign.RemoteHrOrganizationFeignApi;
import com.smedi.ismedi.web.starter.common.ResponseData;
import com.smedi.ismedi.web.starter.exception.BasicError;
import com.smedi.ismedi.web.starter.exception.LogicException;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import com.smedi.ismedi.web.starter.util.SegmentateUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.smedi.ismedi.constructionproject.core.infrastructure.constant.ConstantField.ACCESS_PROJECT;

/**
 * @Author: xulinjun
 * @Date: 2021-6-23 9:33
 */
@Slf4j
@Service
@AllArgsConstructor
public class ProjectBasicQueryServiceImpl implements ProjectBasicQueryService {
    private final OrganizationRemoteApiService organizationRemoteApiService;
    private final ProjectBasicMapper projectBasicMapper;
    private final ProjectBasicDomainService projectBasicDomainService;
    private final ProjectBasicRepository projectBasicRepository;
    private final RemoteHrOrganizationFeignApi remoteHrOrganizationFeignApi;

    private final DozerUtil dozerUtil;
    private final AuthorityUtil authorityUtil;
    private final SegmentateUtil segmentateUtil;

    private void assembleDetailInfo(ProjectBasicVo projectBasicVo) {
        // 获取企业组织信息
        HrOrganizationResponse hrOrganizationResponse = organizationRemoteApiService.getHrOrganizationView(projectBasicVo.getHrOrganizationId());
        if (hrOrganizationResponse != null) {
            projectBasicVo.setHrOrganizationFullName(hrOrganizationResponse.getFullName())
                    .setHrOrganizationShortName(hrOrganizationResponse.getShortName());
        }
        projectBasicVo.setContractDurationDays(projectBasicDomainService.getDurationDays(projectBasicVo.getContractDurationBegin(), projectBasicVo.getContractDurationEnd()))
                .setActualDurationDays(projectBasicDomainService.getDurationDays(projectBasicVo.getActualDurationBegin(), projectBasicVo.getActualDurationEnd()))
                .setProjectStatusMeaning(ProjectStatusEnum.getName(projectBasicVo.getProjectStatus()))
                .setProjectCategoryMeaning(ProjectCategoryEnum.getName(projectBasicVo.getProjectCategory()))
                .setEpcTypeMeaning(EpcTypeEnum.getName(projectBasicVo.getEpcType()));
    }

    @Override
    public IPage getProjectPagination(Long offset, Long pageSize, String projectName, String projectCode, String projectManager, Long hrOrganizationId, boolean containHrOrganizationChildren) {
        Page<ProjectBasicVo> page = new Page<>(offset, pageSize);
        page.addOrder(new OrderItem().ascs("id"));
        IPage<ProjectBasicVo> pagination;

        // 是否包含下级组织
        if (containHrOrganizationChildren) {
            // 根据当前传入的组织id获取到当前组织以及下属组织
            List<Long> hrOrganizationIds = organizationRemoteApiService.getHrOrganizationChildrenOrgIdList(hrOrganizationId);
            List<List<Long>> seg = segmentateUtil.doCut(hrOrganizationIds, 999);
            pagination = projectBasicMapper.selectProjectBasicVoIncludeChildrenPagination(page, projectName, projectCode, projectManager, seg);
        } else {
            pagination = projectBasicMapper.selectProjectBasicVoPagination(page, projectName, projectCode, projectManager, hrOrganizationId);
        }

        pagination.getRecords().stream().forEach(projectBasicVo -> {
            assembleDetailInfo(projectBasicVo);
        });
        return pagination;
    }

    @Override
    public ProjectBasicVo getProjectBasicView(Long projectId) {
        ProjectBasic projectBasic = projectBasicRepository.selectByProjectId(projectId);
        if (projectBasic != null) {
            projectBasic.setContractDurationDays(projectBasicDomainService.getDurationDays(projectBasic.getContractDurationBegin(), projectBasic.getContractDurationEnd()))
                    .setActualDurationDays(projectBasicDomainService.getDurationDays(projectBasic.getActualDurationBegin(), projectBasic.getActualDurationEnd()));

            // 获取企业组织信息
            /*HrOrganizationResponse hrOrganizationResponse = organizationRemoteApiService.getHrOrganizationView(projectBasic.getHrOrganizationId());
            if (hrOrganizationResponse != null) {
                projectBasic.setHrOrganizationFullName(hrOrganizationResponse.getFullName())
                        .setHrOrganizationShortName(hrOrganizationResponse.getShortName());
            }*/

            ProjectBasicVo projectBasicVo = dozerUtil.convertor(projectBasic, ProjectBasicVo.class);
            assembleDetailInfo(projectBasicVo);

            return projectBasicVo;
        } else {
            throw LogicException.raise(CustomError.PROJECT_NOT_EXIST);
        }
    }

    @Override
    public List<ProjectBasicVo> getProjectBasicView(String provinceName) {
        List<ProjectBasicVo> projectBasicVoList = new ArrayList<>();

        List<ProjectBasic> projectBasicList = projectBasicRepository.selectByProvinceName(provinceName);

        if (projectBasicList.isEmpty()) {
            return projectBasicVoList;
        }

        projectBasicList.forEach(projectBasic -> {
            projectBasic.setContractDurationDays(projectBasicDomainService.getDurationDays(projectBasic.getContractDurationBegin(), projectBasic.getContractDurationEnd()))
                    .setActualDurationDays(projectBasicDomainService.getDurationDays(projectBasic.getActualDurationBegin(), projectBasic.getActualDurationEnd()));
            // 获取企业组织信息
            /*HrOrganizationResponse hrOrganizationResponse = organizationRemoteApiService.getHrOrganizationView(projectBasic.getHrOrganizationId());
            if (hrOrganizationResponse != null) {
                projectBasic.setHrOrganizationFullName(hrOrganizationResponse.getFullName())
                        .setHrOrganizationShortName(hrOrganizationResponse.getShortName());
            }*/
            ProjectBasicVo projectBasicVo = dozerUtil.convertor(projectBasic, ProjectBasicVo.class);
            assembleDetailInfo(projectBasicVo);
            projectBasicVoList.add(projectBasicVo);
        });

        return projectBasicVoList;
    }

    @Override
    public IPage getProjectManagementInfoPagination(Long offset, Long pageSize, String projectName, String projectCode, String projectManager, Long hrOrganizationId, String supervisionUnit, String projectStatus, String projectCategory, String contractDurationBegin, String contractDurationEnd) {
        Page<ProjectBasicVo> page = new Page<>(offset, pageSize);
        page.addOrder(new OrderItem().ascs("id"));

        IPage<ProjectBasicVo> pagination = projectBasicMapper.selectProjectManagementInfoPagination(page, projectName, projectCode, projectManager, hrOrganizationId, supervisionUnit, projectStatus, projectCategory, contractDurationBegin, contractDurationEnd, null, null);
        pagination.getRecords().stream().forEach(projectBasicVo -> {
            assembleDetailInfo(projectBasicVo);
        });
        return pagination;
    }

    @Override
    public IPage getProjectManagementInfoPaginationForMobile(Long offset, Long pageSize, String projectName, String projectCode, String projectManager, Long hrOrganizationId, String supervisionUnit, String projectStatus, String projectCategory, String contractDurationBegin, String contractDurationEnd, String epcType) {
        Page<ProjectBasicVo> page = new Page<>(offset, pageSize);
        page.addOrder(new OrderItem().ascs("id"));
        List<Long> projectIds = authorityUtil.getDataScope().getOrDefault(ACCESS_PROJECT, new ArrayList<>());
        if(CollectionUtils.isEmpty(projectIds)){
            return page;
        }
        IPage<ProjectBasicVo> pagination = projectBasicMapper.selectProjectManagementInfoPagination(page, projectName, projectCode, projectManager, hrOrganizationId, supervisionUnit, projectStatus, projectCategory, contractDurationBegin, contractDurationEnd, epcType, projectIds);
        pagination.getRecords().stream().forEach(projectBasicVo -> {
            assembleDetailInfo(projectBasicVo);
        });
        return pagination;
    }

    @Override
    public List<ProjectBasicVo> getAvailableProjectList() {
        ResponseData<List<HrOrganizationResponse>> allHrOrganizationListResponse = remoteHrOrganizationFeignApi.getAllHrOrganizationList();
        List<ProjectBasic> projectBasicList = projectBasicRepository.selectProjectList();

        if (!allHrOrganizationListResponse.isSuccess()) {
            throw LogicException.raise(BasicError.CALL_REMOTE_API_ERROR, allHrOrganizationListResponse.getApplication(), String.valueOf(allHrOrganizationListResponse.getErrorMsg()));
        }

        List<HrOrganizationResponse> hrOrganizationTempList = allHrOrganizationListResponse.getData();

        for (ProjectBasic projectBasicTemp : projectBasicList) {
            for (HrOrganizationResponse hrOrganizationTemp : hrOrganizationTempList) {
                if (projectBasicTemp.getHrOrganizationId().equals(hrOrganizationTemp.getHrOrganizationId())) {
                    projectBasicTemp.setHrOrganizationFullName(hrOrganizationTemp.getFullName());
                }
            }
        }


        return dozerUtil.convertor(projectBasicList, ProjectBasicVo.class);
    }

    @Override
    public List<ProjectBasicVo> getAvailableProjectListWithToken() {
        ResponseData<List<HrOrganizationResponse>> allHrOrganizationListResponse = remoteHrOrganizationFeignApi.getAllHrOrganizationList();
        List<ProjectBasic> projectBasicList = projectBasicRepository.selectProjectListWithToken();

        if (!allHrOrganizationListResponse.isSuccess()) {
            throw LogicException.raise(BasicError.CALL_REMOTE_API_ERROR, allHrOrganizationListResponse.getApplication(), String.valueOf(allHrOrganizationListResponse.getErrorMsg()));
        }

        List<HrOrganizationResponse> hrOrganizationTempList = allHrOrganizationListResponse.getData();

        for (ProjectBasic projectBasicTemp : projectBasicList) {
            for (HrOrganizationResponse hrOrganizationTemp : hrOrganizationTempList) {
                if (projectBasicTemp.getHrOrganizationId().equals(hrOrganizationTemp.getHrOrganizationId())) {
                    projectBasicTemp.setHrOrganizationFullName(hrOrganizationTemp.getFullName());
                }
            }
        }


        return dozerUtil.convertor(projectBasicList, ProjectBasicVo.class);
    }

    @Override
    public Map<Long, List<ProjectBasicVo>> getProjectTree() {
        List<Long> projectIds = authorityUtil.getDataScope().get("project");
        List<ProjectBasicVo> list = dozerUtil.convertor(projectBasicRepository.selectProjectList(), ProjectBasicVo.class);

        // 按照企业组织分组
        return list.stream().filter(projectBasicVo -> projectIds.contains(projectBasicVo.getProjectId())).collect(Collectors.groupingBy(ProjectBasicVo::getHrOrganizationId));
    }

    @Override
    public List<ProjectBasicVo> getProjectBasicListByHrOrganizationIds(List<Long> hrOrganizationIds) {
        List<ProjectBasic> projectBasics = new ArrayList<>();
        hrOrganizationIds.stream().forEach(hrOrganizationId -> {
            projectBasics.addAll(projectBasicRepository.selectByHrOrganizationId(hrOrganizationId));
        });

        List<ProjectBasic> list = projectBasics.stream().distinct().sorted(Comparator.comparing(ProjectBasic::getProjectId).reversed()).collect(Collectors.toList());
        return dozerUtil.convertor(list, ProjectBasicVo.class);
    }

    @Override
    public List<ProjectBasicVo> getQueryProjectBasicListByApp(String appSeach,List<Long> ids) {
        List<ProjectBasic> projectBasics = projectBasicRepository.getQueryProjectBasicListByApp(appSeach,ids);
        List<ProjectBasic> list = projectBasics.stream().distinct().sorted(Comparator.comparing(ProjectBasic::getProjectId).reversed()).collect(Collectors.toList());
        return dozerUtil.convertor(list, ProjectBasicVo.class);
    }

    @Override
    public List<ProjectBasicVo> getProjectBasicViewSimpleList(List<Long> projectIds) {
        List<ProjectBasic> projectBasics = projectIds.stream().map(projectId -> projectBasicRepository.selectByProjectId(projectId))
                .filter(projectBasic -> projectBasic != null).collect(Collectors.toList());
        return dozerUtil.convertor(projectBasics, ProjectBasicVo.class);
    }

    @Override
    public Project getProjectOne(ProjectOneQueryCommand projectOneQueryCommand) {
        ProjectQuery projectQuery = dozerUtil.convertor(projectOneQueryCommand, ProjectQuery.class);
        return projectBasicRepository.getProjectOne(projectQuery);
    }

    @Override
    public List<Project> getProjectList(ProjectListQueryCommand projectListQueryCommand) {
        ProjectQuery projectQuery = dozerUtil.convertor(projectListQueryCommand, ProjectQuery.class);
        return projectBasicRepository.getProjectList(projectQuery);
    }

    @Override
    public Page<ProjectDetailVo> getProjectDetailPage(ProjectPageQueryCommand projectPageQueryCommand) {
        ProjectQuery projectQuery = dozerUtil.convertor(projectPageQueryCommand, ProjectQuery.class);
        return projectBasicRepository.getProjectDetailPage(projectQuery);
    }

    @Override
    public List<ProjectDetailVo> getProjectDetailList(ProjectListQueryCommand projectListQueryCommand) {
        ProjectQuery projectQuery = dozerUtil.convertor(projectListQueryCommand, ProjectQuery.class);
        return projectBasicRepository.getProjectDetailList(projectQuery);
    }

    @Override
    public List<ProjectWithDingVo> getProjectVosByOrgId(Long orgId) {
        List<ProjectWithDing> projectWithDings = projectBasicRepository.selectByOrgId(orgId);
        return dozerUtil.convertor(projectWithDings, ProjectWithDingVo.class);
    }

    @Override
    public ProjectWithDingVo getProjectWithDingVoById(Long id) {
        ProjectWithDing project = projectBasicRepository.selectById(id);
        return dozerUtil.convertor(project, ProjectWithDingVo.class);
    }

    @Override
    public Integer getProjectCount(ProjectCountQueryCommand projectCountQueryCommand) {
        ProjectCountQuery projectCountQuery = dozerUtil.convertor(projectCountQueryCommand, ProjectCountQuery.class);
        return projectBasicRepository.getProjectCount(projectCountQuery);
    }
}
